package com.pai4j.common.service;
import com.aliyun.oss.OSS;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.PutObjectRequest;
import com.pai4j.common.config.properties.AliCloudConfig;
import com.pai4j.common.enums.community.ResourceFormatEnum;
import com.pai4j.common.exception.BusinessException;
import com.pai4j.common.helper.SessionHelper;
import com.pai4j.common.util.*;
import com.pai4j.domain.community.UploadResultVO;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.sql.rowset.serial.SerialBlob;
import java.io.*;
import java.util.Base64;
import java.util.Date;

import static com.pai4j.common.util.DateUtils.YYYYMMDD;

/**
 *  文件上传通用服务类
 *
 * @author: CYM-pai
 * @date: 2025/10/31 11:55
 **/
@Slf4j
@Service
public class FileUploadService {

    @Autowired
    private OSS aliCloudOSSClient;
    @Autowired
    private AliCloudConfig aliCloudConfig;

    @Value("${local.temp.dir}")
    private String localTempDir;

    /**
     * 上传base64到OSS
     *
     * @param path
     * @param fileName
     * @param base64
     * @param openListener
     * @return
     */
    /**
     * 上传base64到OSS
     *
     * @param path
     * @param fileName
     * @param base64
     * @param openListener
     * @return
     */
    public UploadResultVO uploadBase64(String path, String fileName, String base64, boolean openListener) {
        UploadResultVO uploadResultVO = new UploadResultVO();
        byte[] bytes = Base64.getDecoder().decode(base64);
        try {
            // 创建PutObjectRequest对象。
            // 填写Bucket名称、Object完整路径和本地文件的完整路径。Object完整路径中不能包含Bucket名称。
            // 如果未指定本地路径，则默认从示例程序所属项目对应本地路径中上传文件。
            SerialBlob s =  new SerialBlob(bytes);
            InputStream inputStream = s.getBinaryStream();
            uploadResultVO = upload(path, fileName, inputStream, openListener);
        } catch (Exception e) {
            log.error("file upload error.", e);
        }
        return uploadResultVO;
    }

    /***
     * 上传文件
     * @param path OSS路径
     * @param fileName 文件名 调用方随机生成，保证唯一不被覆盖
     * @param fileStream 文件
     * @param openListener 开启上传进度监听
     * @return
     */
    public UploadResultVO upload(String path, String fileName, InputStream fileStream, boolean openListener) {
        UploadResultVO uploadResultVO = new UploadResultVO();
        try {
            // 创建PutObjectRequest对象。
            // 填写Bucket名称、Object完整路径和本地文件的完整路径。Object完整路径中不能包含Bucket名称。
            // 如果未指定本地路径，则默认从示例程序所属项目对应本地路径中上传文件。
            String filePathAndFileName = path.concat("/").concat(fileName);
            PutObjectRequest putObjectRequest = new PutObjectRequest(aliCloudConfig.getOssBucketName(), filePathAndFileName, fileStream);
            // 上传文件。开启上传进度监听器
            if (openListener) {
                aliCloudOSSClient.putObject(putObjectRequest.withProgressListener(new PutObjectProgressListener(SessionHelper.getTaskId(), fileStream.available())));
            } else {
                aliCloudOSSClient.putObject(putObjectRequest);
            }
            uploadResultVO.setFileName(fileName);
            uploadResultVO.setUrl(buildOssFileVisitUrl(path, fileName));
            uploadResultVO.setFileSize(null);
        } catch (Exception e) {
            log.error("file upload error.", e);
        }
        return uploadResultVO;
    }

    public String uploadAndGetUrl(String path, String fileName, InputStream fileStream) {
        UploadResultVO uploadResultVO = upload(path, fileName, fileStream, false);
        if (uploadResultVO.getSuccess()) {
            return uploadResultVO.getUrl();
        }
        return null;
    }

    /***
     * 文件下载
     * @param os
     * @throws IOException
     */
    public void download(OutputStream os, String resourceOSSUrl) throws IOException {

        this.downloadByObjectName(os, getOssResourceObjectName(resourceOSSUrl));
    }

    public void downloadByObjectName(OutputStream os, String objectName) {
        try {
            // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
            OSSObject ossObject = aliCloudOSSClient.getObject(aliCloudConfig.getOssBucketName(), objectName);
            // 读取文件内容。
            BufferedInputStream in = new BufferedInputStream(ossObject.getObjectContent());
            BufferedOutputStream out = new BufferedOutputStream(os);
            byte[] buffer = new byte[1024];
            int lenght;
            while ((lenght = in.read(buffer)) != -1) {
                out.write(buffer, 0, lenght);
            }
            if (out != null) {
                out.flush();
                out.close();
            }
            if (in != null) {
                in.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException("文件下载失败");
        }
    }

    /**
     * 获取 OSS 文件输入流
     * @param resourceUrl
     * @return
     */
    public InputStream getOssFileInputStream(String resourceUrl) {
        String objectName = getOssResourceObjectName(resourceUrl);
        // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
        OSSObject ossObject = aliCloudOSSClient.getObject(aliCloudConfig.getOssBucketName(), objectName);
        // 读取文件内容。
        BufferedInputStream in = new BufferedInputStream(ossObject.getObjectContent());
        return in;
    }

    /***
     * 合成txt文件、并下载
     * @param content
     */
    public void createTxtAndDownload(HttpServletResponse response, String content) {
        try {
            // 生成txt资源
            String filePath = localTempDir + IDGenerateUtil.createId("TXT")+".txt";
            File txt = new File(filePath);
            if (!txt.exists()) {
                txt.createNewFile();
            }
            PrintWriter printWriter = new PrintWriter(txt);
            printWriter.write(content);
            printWriter.flush();
            printWriter.close();
            // 读取文件内容。
            InputStream in = new FileInputStream(filePath);
            OutputStream out = response.getOutputStream();
            byte[] buffer = new byte[1024];
            int lenght;
            while ((lenght = in.read(buffer)) != -1) {
                out.write(buffer, 0, lenght);
            }
            if (out != null) {
                out.flush();
                out.close();
            }
            if (in != null) {
                in.close();
            }
            txt.delete();
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessException("云盘资源下载失败");
        }
    }

    private String buildOssFileVisitUrl(String path, String fileName) {
        return aliCloudConfig.getOssHost().concat(path).concat("/").concat(fileName);
    }
    private String getOssResourceObjectName(String resourceUrl) {
        if (resourceUrl.startsWith("https")) {
            return resourceUrl.substring(aliCloudConfig.getOssHost().length());
        }
        return resourceUrl.substring(aliCloudConfig.getOssHost().length() - 1);
    }

    /***
     * 下载网络资源并上传到自己的OSS
     * @param networkUrl
     * @param path
     * @return
     */
    public UploadResultVO downloadNetworkImageAndUploadOSS(String networkUrl, String path, String format) {
        File file = downloadNetWorkFile(networkUrl, format);
        if (file == null) {
            throw new BusinessException("网络资源下载失败：" + networkUrl);
        }
        MultipartFile multipartFile = FileConvertUtil.convertFileToMultipartFile(file);
        try {
            return this.upload(path, file.getName(), multipartFile.getInputStream(), false);
        } catch (IOException e) {
           log.error("上网络资源到本地异常！", e);
        }
        return null;
    }

    public File downloadNetWorkFile(String netWorkResourceUrl, String format) {
        // 临时下载目录 TEMP_DIR + 今天
        String tempDownloadDir = localTempDir.concat(DateUtils.getDate2String(YYYYMMDD, new Date())).concat("/");
        File dirWithDate = new File(tempDownloadDir);
        if (!dirWithDate.exists()) {
            // 目录不存在时，创建临时目录
            dirWithDate.mkdirs();
        }
        // 文件名称规则
        String fileName =
                tempDownloadDir.concat(FileUtil.generateFileName(System.currentTimeMillis() + "." +format));
        // 下载文件
        File downloadFile = new File(fileName);
        // 下载到本地
        HttpClientUtil.downloadByResourceUrl(netWorkResourceUrl, null, null, downloadFile);
        return downloadFile;
    }

    private String format(String netWorkResourceUrl) {
        return ResourceFormatEnum.getFileExtNameByFileName(netWorkResourceUrl);
    }

    private String extName(String netWorkResourceUrl) {
        return ResourceFormatEnum.getFileExtNameByFileName(netWorkResourceUrl);
    }
}
